package com.hsh.config.shiro;

import com.hsh.config.jwt.JWTToken;
import com.hsh.config.redis.RedisUtil;
import com.hsh.entity.DbRole;
import com.hsh.service.IDbUserService;
import com.hsh.tools.JWTUtils;
import com.hsh.tools.StrUtils;
import com.hsh.tools.decision.AccountStatusEnum;
import com.hsh.vo.dto.ActiveUser;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

//参考:~~~
//https://blog.csdn.net/stilll123456/article/details/88370355?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.control
//自定义realm 需要继承此类
@Service
public class UserRealm extends AuthorizingRealm {

    private final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
    // danger
    @Autowired
    private IDbUserService userService;

    /**
     * 大坑！，必须重写此方法，不然Shiro会报错
     * 参考: https://blog.csdn.net/u012587407/article/details/105102445
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JWTToken;
    }

    /**
     * 只有当需要检测用户权限的时候才会调用此方法，例如checkRole,checkPermission之类的
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("执行了==>授权AuthorizationInfo~~~ ");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        ActiveUser activeUser = (ActiveUser) SecurityUtils.getSubject().getPrincipal();
        // 为后台的最高权限者
        if (Objects.equals(AccountStatusEnum.BOOS.getCode(), activeUser.getUserId())) {
            logger.info("(开始授权)最高权限拥有者~~");
            authorizationInfo.addStringPermission(AccountStatusEnum.BOOS.getDesc());
        } else if (activeUser.isDeptFlag()) {
            logger.info("(开始授权)拥有进入后台资格~~");
            // 授权角色
            List<String> roles = activeUser.getRoles().stream().map(DbRole::getRoleName).distinct().collect(Collectors.toList());
            authorizationInfo.addRoles(roles);

            // 授权权限
            List<String> permissions = activeUser.getPermissions().stream().filter(StrUtils::isNotEmpty).collect(Collectors.toList());
            authorizationInfo.addStringPermissions(permissions);

            System.out.println(authorizationInfo);
        } else {
            throw new AuthorizationException("你没有权限访问！");
        }
        return authorizationInfo;
    }

    /**
     * 默认使用此方法进行用户名正确与否验证，错误抛出异常即可。
     * 认证~~~~~~~
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken tokenAuth) {
        System.out.println("执行了==>认证AuthenticationInfo~~~ ");
        // 校验token
        String token = (String) tokenAuth.getCredentials();
        if (JWTUtils.isExpire(token)) {
            throw new AuthenticationException(" token过期,请重新登入! ");
        }
        ActiveUser activeUser = JWTUtils.getActiveUser(token);
        // 认证token
        if (!JWTUtils.verifyToken(token, activeUser, activeUser.getPassword())) {
            throw new AuthenticationException("密码错误！");
        }
        return new SimpleAuthenticationInfo(activeUser, token, this.getName());
    }
}
